#include "MainPage_gui.h"
#include "lvgl/lvgl.h"
#include "stdio.h"
#include "stdlib.h"

#define WEATHER_ICON_DIR "S:./res/weather_icon/"

#define WEATHER_MISC_FMT "气压%dkPa, 最低气温%d℃, 最高气温%d℃, %s风%d级.   "

LV_IMG_DECLARE(temp_icon)
LV_IMG_DECLARE(humi_icon)

LV_FONT_DECLARE(lv_font_boli_72)
LV_FONT_DECLARE(lv_font_mh_22)
LV_FONT_DECLARE(lv_font_mh_18)
LV_FONT_DECLARE(lv_font_mh_16)
LV_FONT_DECLARE(lv_font_mh_12)

typedef struct 
{
  lv_obj_t *cont;     //天气容器
  lv_obj_t *img;      //显示天气图片
  lv_obj_t *address_label;    //显示地址标签
  lv_obj_t *temp_bar;         //温度进度条
  lv_obj_t *humi_bar;         //湿度进度条
  lv_obj_t *misc_label;        //其他信息label
}WeatherObj;


typedef struct
{
  lv_obj_t *time_label;             //显示时间标签
  lv_obj_t *date_label;             //显示日期标签
  lv_obj_t *app_cont;             //应用程序容器
  WeatherObj weather;         //天气小工具集合
}MainObj;

static void application_click_event_cb(lv_event_t *e);

// LCD分辨率
static uint32_t lcd_w = 480;
static uint32_t lcd_h = 272;

//UI回调函数集合
static gui_opt_t gui_opts;

//主界面背景img
static lv_obj_t *back_img;

//启动界面背景图片
static lv_obj_t *boot_img;

//主界面小工具集合
static MainObj main_obj;


//星期文本
static const char *weekday[] = 
{
   "日", "一", "二", "三", "四", "五", "六"
};

/*
  *@brief 初始化界面UI
  *@param opts UI回调函数集合
  *@param bg_file 主界面壁纸文件名(.bin)
  */
void main_page_gui_init(gui_opt_t *opts, const char *bg_file)
{
  if(opts != NULL)
        memcpy(&gui_opts, opts, sizeof(gui_opt_t));          //拷贝回调函数

    //创建背景图片
    back_img = lv_img_create(lv_scr_act());
    lv_obj_set_size(back_img, lcd_w, lcd_h);
    lv_obj_center(back_img);
    lv_obj_clear_flag(back_img, LV_OBJ_FLAG_SCROLLABLE);       //设置不可滚动
    char path[36];
    sprintf(path, "%s%s", "S:./res/background/", bg_file);
    lv_img_set_src(back_img, path);     //设置背景图片

    //创建主界面元素
  main_obj.time_label = lv_label_create(back_img);        //创建时间label
  lv_obj_set_style_text_font(main_obj.time_label, &lv_font_boli_72, LV_STATE_DEFAULT);      //设置字体
  lv_obj_set_style_text_color(main_obj.time_label, lv_color_hex(0xececec), LV_STATE_DEFAULT);    //字体颜色
  lv_label_set_text(main_obj.time_label, "12:34");
  lv_obj_align(main_obj.time_label, LV_ALIGN_CENTER, 0, -150);

  main_obj.date_label = lv_label_create(back_img);      //创建日期label
  lv_obj_set_style_text_font(main_obj.date_label, &lv_font_mh_18, LV_STATE_DEFAULT);      //设置字体
  lv_obj_set_style_text_color(main_obj.date_label, lv_color_hex(0xececec), LV_STATE_DEFAULT);    //字体颜色
  lv_label_set_text(main_obj.date_label, "2月8日星期三");
  lv_obj_align_to(main_obj.date_label, main_obj.time_label, LV_ALIGN_OUT_BOTTOM_MID, 0, -10);

  main_obj.app_cont = lv_obj_create(back_img);
  lv_obj_set_size(main_obj.app_cont, 700, 200);
  lv_obj_set_scroll_dir(main_obj.app_cont, LV_DIR_HOR);   //只能水平滚动
  lv_obj_set_scrollbar_mode(main_obj.app_cont, LV_SCROLLBAR_MODE_OFF);    //不显示滚动条
  lv_obj_set_style_bg_color(main_obj.app_cont, lv_color_hex(0xeddddd), LV_STATE_DEFAULT);     //背景颜色
  lv_obj_set_style_bg_opa(main_obj.app_cont, LV_OPA_30, LV_STATE_DEFAULT);      //背景透明度
  lv_obj_set_style_border_opa(main_obj.app_cont, LV_OPA_TRANSP, LV_STATE_DEFAULT);      //边框透明
  lv_obj_align(main_obj.app_cont, LV_ALIGN_BOTTOM_MID, 0, -60);

  //创建天气相关元素
  WeatherObj *weather = &main_obj.weather;

  weather->cont = lv_obj_create(back_img);        //创建天气容器
  lv_obj_set_size(weather->cont, 260, 160);
  lv_obj_clear_flag(weather->cont, LV_OBJ_FLAG_SCROLLABLE);   //禁止滚动
  lv_obj_set_style_bg_color(weather->cont, lv_color_hex(0xeddddd), LV_STATE_DEFAULT);     //背景颜色
  lv_obj_set_style_bg_opa(weather->cont, LV_OPA_40, LV_STATE_DEFAULT);      //背景透明度
  lv_obj_set_style_border_opa(weather->cont, LV_OPA_TRANSP, LV_STATE_DEFAULT);      //边框透明
  lv_obj_align(weather->cont, LV_ALIGN_TOP_RIGHT, -20, 20);

  weather->img = lv_img_create(weather->cont);      //创建天气icon
  lv_img_set_src(weather->img, WEATHER_ICON_DIR"0.bin");
  lv_obj_align(weather->img, LV_ALIGN_TOP_RIGHT, 20, -20);

  weather->address_label = lv_label_create(weather->cont);        //创建地址label
  lv_obj_set_style_text_font(weather->address_label, &lv_font_mh_22, LV_STATE_DEFAULT);
  lv_obj_set_style_text_color(weather->address_label, lv_color_hex(0xffffff), LV_STATE_DEFAULT);
  lv_label_set_text(weather->address_label, "定位失败");
  lv_obj_align(weather->address_label, LV_ALIGN_TOP_LEFT, 20, -10);

  lv_obj_t **bar_array[] = {&weather->temp_bar, &weather ->humi_bar};
  const lv_img_dsc_t   *bar_icon[] = {&temp_icon, &humi_icon};
  lv_obj_t *last_img;

  for(int i = 0; i < 2; i++)
  {
    lv_obj_t *img = lv_img_create(weather->cont);       //创建温度湿度相关
    lv_img_set_src(img, bar_icon[i]);
    if(i == 0)
      lv_obj_set_pos(img, -20, 30);
    else
      lv_obj_align_to(img, last_img, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    lv_obj_t *bar = lv_bar_create(weather->cont);
    lv_obj_set_size(bar, 60, 12);
    lv_bar_set_range(bar, -50, 50);       //温度范围-50  ~ 50
    lv_bar_set_value(bar, 22, LV_ANIM_ON);
    lv_obj_set_style_border_width(bar, 2, LV_STATE_DEFAULT);
    lv_obj_set_style_border_color(bar, lv_color_hex(0xffffff), LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(bar, lv_color_hex(0xce6767), LV_PART_INDICATOR | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_all(bar, 1, LV_STATE_DEFAULT);
    lv_obj_align_to(bar, img, LV_ALIGN_OUT_RIGHT_MID, 0, 0);

    lv_obj_t *label = lv_label_create(weather->cont);
    lv_obj_set_style_text_font(label, &lv_font_mh_12, LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(label, lv_color_hex(0xffffff), LV_STATE_DEFAULT);
    lv_label_set_text(label, "22℃");
    lv_obj_align_to(label, bar, LV_ALIGN_OUT_RIGHT_MID, 0, 0);

    lv_obj_set_user_data(bar, label); 

    *(bar_array[i]) = bar;
    last_img = img;
  }
  lv_bar_set_range(weather->humi_bar, 0, 100);       //湿度范围0  ~ 100
  lv_obj_set_style_bg_color(weather->humi_bar, lv_color_hex(0x1454cc), LV_PART_INDICATOR | LV_STATE_DEFAULT);
  lv_label_set_text(lv_obj_get_user_data(weather->humi_bar), "50%");
  lv_bar_set_value(weather->humi_bar, 50, LV_ANIM_ON);

  weather->misc_label = lv_label_create(weather->cont);
  lv_obj_set_size(weather->misc_label, 220, 30);
  lv_label_set_long_mode(weather->misc_label, LV_LABEL_LONG_SCROLL);
  lv_obj_set_style_text_font(weather->misc_label, &lv_font_mh_16, LV_STATE_DEFAULT);
  lv_obj_set_style_text_color(weather->misc_label, lv_color_hex(0xffffff), LV_STATE_DEFAULT);
  lv_label_set_text_fmt(weather->misc_label, WEATHER_MISC_FMT, 900, 10, 20, "东", 1);
  lv_obj_align(weather->misc_label, LV_ALIGN_BOTTOM_MID, 0, 20);
}

/*
  *@brief 更新主界面天气信息
  */
void main_page_gui_update_weather(gui_weather_t *weather)
{
  WeatherObj *w = &main_obj.weather;
  lv_obj_t *bar_label;

  lv_label_set_text(w->address_label, weather->position);
  lv_bar_set_value(w->temp_bar, weather->temp, LV_ANIM_ON);
  lv_bar_set_value(w->humi_bar, weather->humi, LV_ANIM_ON);

  bar_label = lv_obj_get_user_data(w->temp_bar);
  lv_label_set_text_fmt(bar_label, "%d℃", weather->temp);
  bar_label = lv_obj_get_user_data(w->humi_bar);
  lv_label_set_text_fmt(bar_label, "%d%%", weather->humi);

  char path[32];
  sprintf(path, WEATHER_ICON_DIR"%d.bin", weather->code);
  lv_img_set_src(w->img, path);

  lv_label_set_text_fmt(w->misc_label, WEATHER_MISC_FMT, weather->pressure, 
      weather->min_temp, weather->max_temp, weather->wind_dir, weather->wind_level);
  
  lv_label_set_long_mode(w->misc_label, LV_LABEL_LONG_SCROLL);
}

/*
  *@brief 在主界面添加一个app icon
  *@param name 应用程序名称
  *@param exec 应用程序文件路径
  *@param argv 应用程序参数 
  *@param icon 应用程序图标(lv_img)
  */
void main_page_gui_add_application(const char *name, const char *exec, char *const argv[], void *icon)
{
  lv_obj_t *prev_app = lv_obj_get_child(main_obj.app_cont,  -1);      //获取最后创建的app

  int len = strlen(exec) + 1;     //保存app执行文件名称
  char *exec_file = malloc(len);
  strcpy(exec_file, exec);

  lv_obj_t *cont = lv_obj_create(main_obj.app_cont);    //app容器充当背景
  lv_obj_set_size(cont, 160, 180);                                                                                                                                                       
  lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLLABLE);      //禁止滚动
  lv_obj_set_style_bg_color(cont, lv_color_hex(0xffffff), LV_STATE_DEFAULT);     //背景颜色
  lv_obj_set_style_bg_opa(cont, LV_OPA_TRANSP, LV_STATE_DEFAULT);      //背景透明度(默认状态)
  lv_obj_set_style_bg_opa(cont, LV_OPA_50, LV_STATE_PRESSED);      //背景透明度(按下状态)
  lv_obj_set_style_border_opa(cont, LV_OPA_TRANSP, LV_STATE_DEFAULT);      //边框透明
  lv_obj_set_user_data(cont, exec_file);      
  lv_obj_add_flag(cont, LV_OBJ_FLAG_CLICKABLE);     //设置可点击
  lv_obj_add_event_cb(cont, application_click_event_cb, LV_EVENT_SHORT_CLICKED, (void *)argv);

  if(prev_app != NULL)      //设置对齐
    lv_obj_align_to(cont, prev_app, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
  else
    lv_obj_align(cont, LV_ALIGN_LEFT_MID, 0, 0);

  lv_obj_t *img = lv_img_create(cont);     //app图标
  lv_img_set_src(img, icon);      //设置图标
  lv_obj_align(img, LV_ALIGN_TOP_MID, 0, -10);
  lv_obj_add_flag(img, LV_OBJ_FLAG_EVENT_BUBBLE);

  lv_obj_t *label = lv_label_create(cont);      //app名称标签
  lv_obj_set_style_text_font(label, &lv_font_mh_16, LV_STATE_DEFAULT);
  lv_obj_set_style_text_color(label, lv_color_hex(0x454545), LV_STATE_DEFAULT);    //字体颜色
  lv_label_set_text(label,name);
  lv_obj_align(label, LV_ALIGN_BOTTOM_MID, 0, 10);
}

/*
  *@brief 释放界面UI
  */
void main_page_gui_release(void)
{
  lv_obj_t *app_cont;

  while((app_cont = lv_obj_get_child(main_obj.app_cont, -1)) != NULL)
  {
    char *exec_file = lv_obj_get_user_data(app_cont);

    free((void *)exec_file);    //释放保存的app数据

    lv_obj_del(app_cont);
  }

  lv_obj_del(back_img);
}

/*
  *@brief 初始化启动界面UI
  */
void main_page_gui_boot_init(void)
{
  lv_obj_t *par = lv_layer_top();     //创建到top layer上以覆盖主界面UI

  // 获取显示设备分辨率
  lcd_w = lv_disp_get_hor_res(NULL);
  lcd_h = lv_disp_get_ver_res(NULL);

  boot_img = lv_img_create(par);
  lv_obj_set_size(boot_img, lcd_w, lcd_h);
  lv_obj_center(boot_img);
  lv_obj_clear_flag(boot_img, LV_OBJ_FLAG_SCROLLABLE);       //设置不可滚动
  lv_img_set_src(boot_img, "S:./res/background/bootbg.bin");

  lv_obj_t *boot_logo = lv_gif_create(boot_img);    //创建giflogo
  lv_gif_set_src(boot_logo, "S:./res/background/bootlogo.gif");
  lv_obj_align(boot_logo, LV_ALIGN_CENTER, 0, -50);

  lv_obj_t *boot_spinner = lv_spinner_create(boot_img, 1000, 60);     //创建旋转加载器
  lv_obj_set_size(boot_spinner, 100, 100);
  lv_obj_set_style_arc_opa(boot_spinner, LV_OPA_TRANSP, LV_STATE_DEFAULT);
  lv_obj_set_style_arc_color(boot_spinner, lv_color_hex(0xffffff), LV_PART_INDICATOR | LV_STATE_DEFAULT);
  lv_obj_align_to(boot_spinner, boot_logo, LV_ALIGN_OUT_BOTTOM_MID, 0, 60);

  lv_obj_t *boot_label = lv_label_create(boot_img);
  lv_obj_set_style_text_font(boot_label, &lv_font_mh_22, LV_STATE_DEFAULT);
  lv_obj_set_style_text_color(boot_label, lv_color_hex(0xffffff), LV_STATE_DEFAULT);
  lv_obj_align(boot_label, LV_ALIGN_BOTTOM_MID, 0, -80);
  lv_label_set_text(boot_label, "系统初始化");

  lv_obj_set_user_data(boot_img, boot_label);
  lv_obj_set_user_data(boot_label, boot_spinner);
}

/*
  *@brief 更新启动界面UI
  *@param progress 启动进度百分比 0~100
  *@param text 启动进度提示文本
  */
void main_page_gui_boot_update(const char *text)
{
  lv_obj_t *label = lv_obj_get_user_data(boot_img);

  lv_label_set_text(label, text);

  if(strcmp(text, "欢迎使用") == 0)
  {
    lv_obj_t *spinner = lv_obj_get_user_data(label);
    if(spinner != NULL)
      lv_obj_del_async(spinner);
  }

  lv_obj_invalidate(lv_scr_act());    //重绘屏幕
}

/*
  *@brief 释放启动界面UI
  */
void main_page_gui_boot_release(void)
{
  lv_obj_del_async(boot_img);
}

/*
  *@brief 更新时间显示
  */
void main_page_gui_update_date(gui_time_t *time)
{
  char buf[32];

  memset(buf, 0, 32);
  buf[0] = time->hour / 10 + '0';
  buf[1] = time->hour % 10 + '0';
  buf[2] = ':';
  buf[3] = time->min / 10 + '0';
  buf[4] = time->min % 10 + '0';

  lv_label_set_text(main_obj.time_label, buf);      //设置时间文本

  sprintf(buf, "%d月%d日 星期%s", time->month, time->day, weekday[time->week]);
  lv_label_set_text(main_obj.date_label, buf);      //设置日期文本
}

/*
  *@brief 应用程序icon点击事件回调函数
  */
static void application_click_event_cb(lv_event_t *e)
{
  lv_obj_t *cont = lv_event_get_target(e);

  const char *exec = lv_obj_get_user_data(cont);
  char *const *argv = lv_event_get_user_data(e);

  printf("click event cb, exec:%s,argv:", exec);

  for(int i = 0; argv[i] != NULL; i++)
    printf("%s ", argv[i]);

  printf("\n");

  if(exec != NULL && argv != NULL)
  {
    if(gui_opts.run_app != NULL)
    {
      gui_opts.run_app(exec, argv);     //运行应用程序,应用程序退出前阻塞在此
      lv_obj_invalidate(lv_scr_act());    //重绘屏幕
    }
  }
}
